#include "game.h"
#include <fstream>
#include "../core/scene.h"
#include "../entity/sceneMain.h"
#include "../entity/sceneTitle.h"
#include "../core/screen.h"
#include "../affiliate/sprite.h"
void game::ready(const char* title,glm::vec2 size)
{
    screen_size = size;
    SDL_Log("ready start");
    if(!SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO)){
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_Init Error: %s", SDL_GetError());
        return;
    }
    //SDL_mix初始化
    if(Mix_Init(MIX_INIT_MP3 | MIX_INIT_OGG) != (MIX_INIT_MP3 | MIX_INIT_OGG)){
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Mix_OpenAudio init Error: %s", SDL_GetError());
        return;
    }
    if(!Mix_OpenAudio(0,nullptr)){
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Mix_OpenAudio Error: %s", SDL_GetError());
        return;
    }
    Mix_AllocateChannels(16);
    Mix_Volume(-1,MIX_MAX_VOLUME/4);
    Mix_VolumeMusic(MIX_MAX_VOLUME/4);
    //SDL_ttf初始化
    if(!TTF_Init()){
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "TTF_Init Error: %s", SDL_GetError());
        return;
    }
    SDL_CreateWindowAndRenderer(title,static_cast<int>(size.x),static_cast<int>(size.y),
        SDL_WINDOW_RESIZABLE,&window,&renderer);
        //printf("x:%f,y:%f,r:%f,g:%f,t:%f\n",size.x,size.y,size.r,size.g,size.t);
    if(window == nullptr || renderer == nullptr){
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateWindowAndRenderer Error: %s", SDL_GetError());
        return;
    }
    SDL_SetRenderLogicalPresentation(renderer,static_cast<int>(size.x),static_cast<int>(size.y),
        SDL_LOGICAL_PRESENTATION_LETTERBOX);
    ttfEngine = TTF_CreateRendererTextEngine(renderer);
    if(ttfEngine == nullptr){
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "TTF_CreateRendererTextEngine Error: %s", SDL_GetError());
        return;
    }
    frame_Delay = 1000000000 / FPS; //1000000000纳秒=1秒
    asset_store = new assetStore(renderer);

    //current_scene = new sceneMain();
    current_scene = new sceneTitle();
    current_scene->init();
    SDL_Log("ready end");
}


void game::run()
{
    float dt = 0.0f;
    ready("GhostEscape",glm::vec2(1200,800));
    SDL_Log("run start");
    while (isRun)
    {
        auto frame_start = SDL_GetTicksNS();
        if(next_scene){
            changeScene(next_scene);
            next_scene = nullptr;
        }
        //SDL_Log("handleEvents");
        handleEvents();
        //SDL_Log("update");
        update(dt);
        //SDL_Log("render");
        render();
        auto frame_end = SDL_GetTicksNS();
        auto elapsed = frame_end - frame_start;
        if(elapsed < frame_Delay){
            SDL_DelayNS(frame_Delay - elapsed);
            dt = frame_Delay / 1.0e9;
        }else{
            dt = elapsed / 1.0e9;
        }
        //SDL_Log("FPS:%f,dt:%f",1.0 / dt,dt);
    }
    SDL_Log("run end");
    clean();
}

void game::clean()
{
    SDL_Log("clean start");
    if(asset_store != nullptr){
        asset_store->clean();
        delete asset_store;
    }
    if(current_scene != nullptr){
        current_scene->clean();
        delete current_scene;
    }
    TTF_Quit();
    Mix_HaltMusic();
    Mix_CloseAudio();
    if(ttfEngine != nullptr){
        TTF_DestroyRendererTextEngine(ttfEngine);
    }
    if(renderer != nullptr){
       SDL_DestroyRenderer(renderer); 
    }
    if(window != nullptr){
        SDL_DestroyWindow(window);
    }
    SDL_Quit();
    SDL_Log("clean end");
}

void game::update(float dt)
{
    updateMouse();
    current_scene->update(dt);
}

void game::render()
{    
    //SDL_Log("render start");
    SDL_SetRenderDrawColor(renderer,0,0,0,255);
    SDL_RenderClear(renderer);
    current_scene->render();
    SDL_RenderPresent(renderer);
    //SDL_Log("render end");
}

void game::handleEvents()
{
    //SDL_Log("handleEvents start");
    SDL_Event event;
    while (SDL_PollEvent(&event))
    {
        switch (event.type)
        {
        case SDL_EVENT_QUIT:
            isRun = false;
            break;

        default:
            current_scene->handleEvents(event);
            break;
        }
    }
    //SDL_Log("handleEvents end");
}

void game::drawGrid(const glm::vec2 &top_left, const glm::vec2 &bottom_right, float grid_size, SDL_FColor color)
{
    SDL_SetRenderDrawColorFloat(renderer,color.r,color.g,color.b,color.a);
    for(float x = top_left.x; x <= bottom_right.x; x += grid_size){
        SDL_RenderLine(renderer,x,top_left.y,x,bottom_right.y);
    }
    for(float y = top_left.y; y <= bottom_right.y; y += grid_size){
        SDL_RenderLine(renderer,top_left.x,y,bottom_right.x,y);
    }
    SDL_SetRenderDrawColorFloat(renderer,0,0,0,1);
}

void game::drawBoundray(const glm::vec2 &top_left, const glm::vec2 &bottom_right, 
        float bottom_wihth, SDL_FColor color)
{
    SDL_SetRenderDrawColorFloat(renderer,color.r,color.g,color.b,color.a);
    for(float i = 0; i < bottom_wihth; i++){
        SDL_FRect rect = {
            top_left.x - i,
            top_left.y - i,
            bottom_right.x - top_left.x + 2 * i,
            bottom_right.y - top_left.y + 2 * i
        }; 
        SDL_RenderRect(renderer,&rect);
    }
    SDL_SetRenderDrawColorFloat(renderer,0,0,0,1);
}

void game::drawPoint(const std::vector<glm::vec2> &points, glm::vec2 position, SDL_FColor color)
{
    SDL_SetRenderDrawColorFloat(renderer,color.r,color.g,color.b,color.a);
    for(auto &point : points){
        SDL_RenderPoint(renderer,position.x + point.x,position.y + point.y);
    }
    SDL_SetRenderDrawColorFloat(renderer,0,0,0,1);
}

void game::renderSprite(const sprite_data &data_, const glm::vec2 &position, 
    const glm::vec2 &size ,const glm::vec2& mask )
{
    SDL_FRect src = {
        data_.src.x,
        data_.src.y + data_.src.h * (1 - mask.y),
        data_.src.w * mask.x,
        data_.src.h * mask.y
    };
    SDL_FRect dst = {
        position.x,
        position.y + size.y * (1 - mask.y),
        size.x * mask.x,
        size.y * mask.y
    };
    SDL_RenderTextureRotated(renderer,data_.texture,&src,&dst,static_cast<double>( data_.angle)
    ,nullptr,data_.isFlip?SDL_FLIP_HORIZONTAL:SDL_FLIP_NONE);
}

void game::renderFillCircle(const glm::vec2 &position, const glm::vec2 &size, float alpha)
{
    auto texture = asset_store->getImage("./assets/UI/circle.png");
    SDL_FRect dst_rect = {
        position.x, position.y, size.x, size.y
    };
    SDL_SetTextureAlphaModFloat(texture, alpha);
    SDL_RenderTexture(renderer, texture, NULL, &dst_rect);
}

void game::renderHbar(const glm::vec2 &position, const glm::vec2 &size, float percent, SDL_FColor color)
{
    SDL_FRect dst_rect = {
        position.x, position.y, size.x, size.y
    };
    SDL_FRect fill_rect = {
        position.x, position.y, size.x * percent, size.y
    };
    SDL_SetRenderDrawColorFloat(renderer,color.r,color.g,color.b,color.a);
    SDL_RenderRect(renderer,&dst_rect);
    SDL_RenderFillRect(renderer,&fill_rect);
    SDL_SetRenderDrawColorFloat(renderer,0,0,0,1);
}

TTF_Text *game::createText(const char *text, const char *font_path, int font_size)
{
    auto font = asset_store->getFont(font_path,font_size);
    return TTF_CreateText(ttfEngine,font,text,font_size);
}

void game::updateMouse()
{
    mouse_buttons = SDL_GetMouseState(&mouse_position.x,&mouse_position.y);
    SDL_SetWindowAspectRatio(window,screen_size.x/screen_size.y,screen_size.x/screen_size.y);
    SDL_FRect rect;
    SDL_GetRenderLogicalPresentationRect(renderer,&rect);
    mouse_position = (mouse_position - glm::vec2(rect.x,rect.y)) * 
        screen_size / glm::vec2(rect.w,rect.h);
}

void game::setScore(int score_)
{
    SDL_Log("setScore %d",score_);
    this->score = score_;
    if(this->score > highscore){
        highscore = this->score;
        SDL_Log("highscore %d",highscore);
    }
}

void game::addScore(int score_)
{
    setScore(this->score + score_);
}

void game::changeScene(scene * scene_)
{
    if(current_scene){
        current_scene->clean();
        delete current_scene;
    }
    current_scene = scene_;
    current_scene->init();
}

std::string game::loadTextFile(const char *path)
{
    std::fstream file(path);
    std::string line;
    std::string text;
    if(file.is_open()){
        while(std::getline(file,line)){
            text += line + "\n";
        }
    }
    return text;
}
